#include <glib.h>
#include <gtk/gtk.h>
#include <SDL.h>
#include "racanhack.h"
#include "task.h"
#include "video.h"
#include "cave.h"
#include "player.h"
#include "monster.h"
#include "monster2.h"
#include "object.h"
#include "object2.h"
#include "stair.h"
#include "floor.h"
#include "turn.h"
#include "los.h"
#include "mapchips.h"
#include "lookdown.h"
#include "game.h"
#include "main.h"

enum {
  FLOOR_LAYER_MAX = 27
};

static struct _floor *floor_layer_start;

static void monsterhouse_add();
static state game_constract(struct _task *task);
static state game_idle_tutorial(struct _task *task);
static state game_idle(struct _task *task);
static state game_deconstract(struct _task *task);

void monsterhouse_add()
{
  struct _room *room;
  int n;
  struct _coord c;
  n = g_random_int_range(0, g_list_length(curf->cave.room_list));
  room = g_list_nth_data(curf->cave.room_list, n);
  room->monsterhouse = TRUE;
  for (c.x = room->lx; c.x <= room->hx; c.x++) {
    for (c.y = room->ly; c.y <= room->hy; c.y++) {
      if (g_random_int_range(0, 4) == 0) {
	monster_add_monsterhouse(c);
      };
      if (g_random_int_range(0, 8) == 0) {
	object_add_monsterhouse(c);
      };
    };
  };
}

void game_trans_state(state (*fp)(struct _task *task), struct _game *game)
{
  if (game->task != NULL)  game->task->alive = FALSE;
  game->task = task_add(fp, game);
}

void game_player_trans_state(state (*fp)(struct _task *task), struct _game *game, struct _player *player)
{
  struct _task *task;
  if (game->task != NULL)  game->task->alive = FALSE;
  if (player->task != NULL) player->task->alive = FALSE;
  task = task_add(fp, game, player);
  game->task = task;
  player->task = task;
}

struct _game *game_add()
{
  struct _game *game;
  game = &Game;
  game->task = NULL;
  return game;
}

state game_opening(struct _task *task)
{
  struct _game *game;
  static struct _sprite *opening_title;
  static struct _sprite *opening_press;
  game = (struct _game *)task->pointer[0];
  if (task->count == 0) {
    SDL_Surface *s;
    s = video_bmp_load("bmp/opening_title.bmp");
    opening_title = video_sprite_add(0);
    opening_title->x = 180;
    opening_title->y = 180;
    opening_title->abs = TRUE;
    opening_title->surface = s;
    s = video_bmp_load("bmp/opening_press.bmp");
    opening_press = video_sprite_add(0);
    opening_press->x = 180;
    opening_press->y = 300;
    opening_press->abs = TRUE;
    opening_press->surface = s;
    video_flamme(TRUE);
  };
  if (keys[SDLK_SPACE]) {
    SDL_FreeSurface(opening_title->surface);
    opening_title->alive = FALSE;
    SDL_FreeSurface(opening_press->surface);
    opening_press->alive = FALSE;
    video_flamme(FALSE);
    video_fade();
    game_trans_state(game_constract, game);
    return;
  };
  if (keys[SDLK_RETURN]) {
    SDL_FreeSurface(opening_title->surface);
    opening_title->alive = FALSE;
    SDL_FreeSurface(opening_press->surface);
    opening_press->alive = FALSE;
    gtk_widget_destroy(main_window);
    return;
  };
}

static state game_constract(struct _task *task)
{
  struct _game *game;
  struct _floor *floor_tutorial;
  struct _floor *floor_layer[FLOOR_LAYER_MAX];
  int i, j;
  struct _floor *src_floor, *dest_floor;
  struct _stair *src_stair, *dest_stair;
  struct _object *ration;
  game = (struct _game *)task->pointer[0];
  player_init();
  monster_init();
  object_init();
  stair_init();
  floor_init();
  turn_init();
  los_init();
  mapchips_init();
  lookdown_init();
  for (i = 0; i < FLOOR_LAYER_MAX; i++) {
    floor_layer[i] = floor_add();
    floor_layer[i]->level = i;
    floor_curf_set(floor_layer[i]);
    if (g_random_int_range(0, 20) == 0) monsterhouse_add();
    for (j = g_random_int_range(4, 8);j > 0;j--) monster_add();
    for (j = g_random_int_range(3, 6);j > 0;j--) object_add();
    if (i == FLOOR_LAYER_MAX - 1) object_add_specify_id(OBJECT_ID_AMUYENDOR);
  };
  for (i = 0; i < FLOOR_LAYER_MAX - 1; i++) {
    src_floor = floor_layer[i];
    dest_floor = floor_layer[i + 1];
    floor_curf_set(src_floor);
    src_stair = stair_add(STAIR_TYPE_DOWN);
    floor_curf_set(dest_floor);
    dest_stair = stair_add(STAIR_TYPE_UP);
    src_stair->dest_stair = dest_stair;
    dest_stair->dest_stair = src_stair;
  };
  floor_layer_start = floor_layer[0];
  floor_tutorial = floor_tutorial_add();
  floor_curf_set(floor_tutorial);
  ration = object_add_specify_id(OBJECT_ID_RATION);
  src_stair = stair_add(STAIR_TYPE_DOWN);
  src_stair->tutorial_floor = TRUE;
  floor_curf_restore();
  player_trans_state(player_action_end, player_add());
  turn_trans_state(turn_player_turn_start, turn_add());
  mapchips_trans_state(mapchips_update, mapchips_add());
  lookdown_trans_state(lookdown_hide, lookdown_add());
  game_trans_state(game_idle_tutorial, game);
  return;
}

static state game_idle_tutorial(struct _task *task)
{
  struct _game *game;
  game = (struct _game *)task->pointer[0];
  if (task->count == 0) {
    msg("To move, press [h,j,k,l]."); 
    msg("To display a lookdown radar, press [shift].");
  };
  if (task->count == 300) {
    msg("Let's move to a symbol ':'. It stands for the something edible."); 
  };
  if ((game->pre_player.coord.x != Player.coord.x) ||
      (game->pre_player.coord.y != Player.coord.y)) {
    if (is_object(Player.coord) != NULL) {
      msg("To pick up, press [r].");
      msg("To open Inventory, press [i].");
    };
    if (is_stair(Player.coord) != NULL) {
      msg("To go down the staircase, press [a].");
      msg("To go up the staircase, press [A].");
    };
  };
  game_idle(task);
};

static state game_idle(struct _task *task)
{
  struct _game *game;
  game = (struct _game *)task->pointer[0];
  if (keys[SDLK_RETURN]) {
    game_trans_state(game_deconstract, game);
    return;
  };
  if ((game->pre_player.coord.x != Player.coord.x) ||
      (game->pre_player.coord.y != Player.coord.y)) {
    los_trans_state(los_update, &Los);
    mapchips_trans_state(mapchips_update, &Mapchips);
  };
  if ((game->pre_curf_level != curf->level) ||
      (game->pre_player.lev != Player.lev) ||
      (game->pre_player.mhp != Player.mhp) ||
      (game->pre_player.chp != Player.chp) ||
      (game->pre_player.cstr != Player.cstr) ||
      (game->pre_player.mstr != Player.mstr) ||
      (game->pre_player.food != Player.food) ||
      (game->pre_player.weapon != Player.weapon) ||
      (game->pre_player.shield != Player.shield)) {
    gchar buf[128];
    GdkRectangle invalid_rectangle;
    g_snprintf(buf, 128, "HP %d/%d\n", Player.chp, Player.mhp);
    gtk_label_set_text(GTK_LABEL(status_hp_label), buf);

    invalid_rectangle.x = 0;
    invalid_rectangle.y = 0;
    invalid_rectangle.width = status_hp_bar->allocation.width;
    invalid_rectangle.height = status_hp_bar->allocation.height;
    gdk_window_invalidate_rect(status_hp_bar->window, &invalid_rectangle, FALSE);
    g_snprintf(buf, 128, "Dungeon Level %d. \n"
	       "LEVEL %d\n"
	       "STR %d/%d\n"
	       "ATK %d AC %d\n"
	       "FOOD %d\n",
	       curf->level,
	       Player.lev,
	       Player.cstr, Player.mstr,
	       object_atk(Player.weapon),
	       object_ac(Player.shield),
	       Player.food);
    gtk_label_set_text(GTK_LABEL(status_label), buf);
  };
  game->pre_curf_level = curf->level;
  game->pre_player = Player;
};

state game_player_next_floor(struct _task *task)
{
  struct _game *game;
  struct _player *player;
  GList *li;
  struct _monster *monster;
  struct _stair *stair;
  struct _stair *dest_stair;
  game = (struct _game *)task->pointer[0];
  player = (struct _player *)task->pointer[1];
  for (li = g_list_first(curf->monster_list); li != NULL; li = g_list_next(li)) {
    monster = (struct _monster *)li->data;
    monster->chp = monster_mhp(monster);
  };
  floor_curf_store();
  stair = is_stair(player->coord);
  if (stair->tutorial_floor == FALSE) {
    dest_stair = stair->dest_stair;
    floor_curf_set(dest_stair->root_floor);
    floor_curf_restore();
    player->coord = dest_stair->coord;
  } else {
    msg("To Fight with monster, Press f-key.");
    floor_curf_set(floor_layer_start);
    floor_curf_restore();
    player->coord = rand_coord();
  };
  player->sprite->x = player->coord.x * SPRITE_W;
  player->sprite->y = player->coord.y * SPRITE_H;
  player_trans_state(player_action_end, player);
  turn_trans_state(turn_player_turn_start, &Turn);
  Lookdown.mapdetect = FALSE;
  Lookdown.mondetect = FALSE;
  Lookdown.objdetect = FALSE;
  video_fade();
  game_trans_state(game_idle, game);
  return;
}

state game_player_killed(struct _task *task)
{
  struct _game *game;
  struct _player *player;
  static struct _sprite *rip;
  game = (struct _game *)task->pointer[0];
  player = (struct _player *)task->pointer[1];
  if (task->count == 0) {
    SDL_Surface *s;
    s = video_bmp_load("bmp/rip.bmp");
    rip = video_sprite_add(Z_ORDER_RIP);
    rip->x = 95;
    rip->y = 180;
    rip->abs = TRUE;
    rip->surface = s;
    msg("Rest in peace... %s", player->died_from);
    msg("To quit the game, hit a return key.");
  };
  if (keys[SDLK_RETURN]) {
    SDL_FreeSurface(rip->surface);
    rip->alive = FALSE;
    game_trans_state(game_deconstract, game);
    return;
  };
};

state game_player_get_amulet_of_yendor(struct _task *task)
{
  struct _game *game;
  struct _player *player;
  game = (struct _game *)task->pointer[0];
  player = (struct _player *)task->pointer[1];
  g_print("%s\n", "You ascended!");
  game_trans_state(game_deconstract, game);
  return;
};
 
static state game_deconstract(struct _task *task)
{
  struct _game *game;
  game = (struct _game *)task->pointer[0];
  player_free();
  monster_free();
  object_free();
  stair_free();
  floor_free();
  turn_free();
  los_free();
  mapchips_free();
  lookdown_free();
  gtk_widget_destroy(main_window);
}
